package com.hollysys.usersync.utils;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 批量调用工具类
 *
 * @author Jeremy Yim
 * @date 2022-04-12
 */
public class ExecuteUtil {

    /**
     * 异步调用
     *
     * @param dataList        源数据
     * @param executorService 线程池
     * @param function        消费
     * @return 返回列表
     */
    public static <T, V> List<AsyncResult<T, V>> batchAsyncCall(List<T> dataList, ExecutorService executorService,
                                                                Function<T, V> function) {
        if (CollectionUtils.isEmpty(dataList)) {
            return new ArrayList<>(0);
        }
        List<CompletableFuture<V>> completableFutures = dataList.stream().map(data -> {
            if (executorService == null) {
                return CompletableFuture.supplyAsync(() -> function.apply(data));
            } else {
                return CompletableFuture.supplyAsync(() -> function.apply(data), executorService);
            }
        }).collect(Collectors.toList());

        CompletableFuture<Void> allFinished = CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
        try {
            allFinished.get();
        } catch (Exception ignored) {
        }

        return Stream.iterate(0, i -> i + 1).limit(dataList.size()).map(i -> {
            try {
                return new AsyncResult<>(dataList.get(i), completableFutures.get(i).join(), true, null);
            } catch (Exception e) {
                return new AsyncResult<T, V>(dataList.get(i), null, false, e.getCause().getMessage());
            }
        }).collect(Collectors.toList());
    }


    /**
     * 执行结果
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public static class AsyncResult<T, V> {

        /**
         * 原始入参
         */
        private T rawParam;

        /**
         * 执行返回
         */
        private V value;

        /**
         * 执行结果
         */
        private Boolean result;

        /**
         * 错误信息
         */
        private String exceptionMessage;

    }
}
